package com.denghq.projectbuilder.component.aif.service;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import com.denghq.projectbuilder.component.aif.utils.JsonUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.HttpClients;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import com.denghq.projectbuilder.component.aif.GetNode;
import com.denghq.projectbuilder.component.aif.RegisterConfig;
import com.denghq.projectbuilder.component.aif.Scheme;
import com.denghq.projectbuilder.component.aif.utils.RestTemplateUtils;

/**
 * @program: key-areas-security-control
 * @description: api接口注册
 * @author: Liu yang
 * @create: 2018-10-17 10:04
 **/
@Component
public class MicroServiceCaller {

	@Autowired
	private RegisterConfig registerConfig;

	@Value("${server.port}")
	String port;

	@Autowired
	RestTemplate restTemplate;

	// 获取微服务接口的请求地址
	public String getApiReqUrl(String path, Scheme scheme) {
		GetNode node = new GetNode();
		node.setPath(path);
		if (scheme != null) {
			node.setScheme(scheme.toValue());
		}
		return getApiReqUrl(node);
	}

	// 获取微服务接口的请求地址
	public String getApiReqUrl(GetNode node) {
		if (StringUtils.isBlank(node.getScheme())) {
			node.setScheme(Scheme.HTTP.toValue());
		}
		String requestBody = JsonUtil.beanToString(node);
		// 请求注册中心的getNode 返回对应的 接口ip和port
		HttpHeaders requestHeaders = new HttpHeaders();
		requestHeaders.setContentType(MediaType.APPLICATION_JSON);// text/css
		HttpEntity<String> httpEntity = new HttpEntity<String>(requestBody, requestHeaders);
		ResponseEntity<String> responseEntity = restTemplate.postForEntity(registerConfig.getGetServiceNodeUrl(),
				httpEntity, String.class);
		if (responseEntity.getBody() == null || "null".equals(responseEntity.getBody())) {
			return null;
		}
		// 注册服务中心访问接口url
		StringBuffer serviceUrl = new StringBuffer(node.getScheme()).append("://")
				.append(responseEntity.getBody().split("\"")[1]);
		return serviceUrl.toString() + node.getPath();

	}
	// 调用微服务接口，返回请求数据
	public <T> T callApi(String path, Scheme scheme, String httpMethod,Boolean paramsDataInQuery, Object params, Map<String, String> heads,
						 Class<T> resultType) {
		HttpMethod method = HttpMethod.valueOf(httpMethod);
		if (paramsDataInQuery == null) {
			paramsDataInQuery = false;
		}
		return callApi(path, scheme, method, params, paramsDataInQuery, heads, resultType);
	}



	// 调用微服务接口，返回请求数据
	public <T> T callApi(String path, Scheme scheme, String httpMethod, Object params, Map<String, String> heads,
			Class<T> resultType) {
		HttpMethod method = HttpMethod.valueOf(httpMethod);
		Boolean reqDataInQuery;
		if (HttpMethod.GET == method || HttpMethod.DELETE == method) {
			reqDataInQuery = true;
		} else {
			reqDataInQuery = false;
		}

		return callApi(path, scheme, method, params, reqDataInQuery, heads, resultType);
	}

	// 调用微服务接口，返回请求数据
	public <T> T callApi(String path, Scheme scheme, HttpMethod httpMethod, Object params, Boolean reqDataInQuery,
			Map<String, String> heads, Class<T> resultType) {
		
		Map<String, Object> queryParams = null;
		Object bodyData = null;
		
		if (reqDataInQuery!=null&&reqDataInQuery) {
			if (params != null) {
				queryParams = transBean2Map(params);
			}
			bodyData = params;
		}else{
			bodyData = params;
		}
		return callApi(path, scheme, httpMethod, queryParams , bodyData, heads, resultType); 
	}

	// Bean --> Map 1: 利用Introspector和PropertyDescriptor 将Bean --> Map
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static Map<String, Object> transBean2Map(Object obj) {

		if (obj == null) {
			return null;
		}

		Map<String, Object> map = new HashMap<String, Object>();
		if (obj instanceof Map) {
			map.putAll((Map) obj);
			return map;
		}
		try {
			BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
			PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
			for (PropertyDescriptor property : propertyDescriptors) {
				String key = property.getName();

				// 过滤class属性
				if (!key.equals("class")) {
					// 得到property对应的getter方法
					Method getter = property.getReadMethod();
					Object value = getter.invoke(obj);

					map.put(key, value);
				}

			}
		} catch (Exception e) {
			System.out.println("transBean2Map Error " + e);
		}

		return map;

	}

	/**
	 * 调用微服务
	 * @param path 请求路径
	 * @param httpMethod 请求方法
	 * @param queryParams 请求参数（url中）
	 * @param bodyData 请求数据（body中）
	 * @param heads 请求头
	 * @param resultType 返回数据类型
	 */
	public <T> T callApi(String path, Scheme scheme, String httpMethod,
			Map<String, Object> queryParams, Object bodyData, Map<String, String> heads, Class<T> resultType) {

		return callApi(path, scheme, HttpMethod.valueOf(httpMethod), queryParams, bodyData, heads, resultType);
	}

	
	/**
	 * 调用微服务
	 * @param path 请求路径
	 * @param httpMethod 请求方法
	 * @param queryParams 请求参数（url中）
	 * @param bodyData 请求数据（body中）
	 * @param heads 请求头
	 * @param resultType 返回数据类型
	 */
	public <T> T callApi(String path, Scheme scheme, HttpMethod httpMethod,
			Map<String, Object> queryParams, Object bodyData, Map<String, String> heads, Class<T> resultType) {

		if (heads == null) {
			heads = new HashMap<String, String>();
		}
		String apiReqUrl = getApiReqUrl(path, scheme);

		if (queryParams != null) {
			StringBuffer queryString = new StringBuffer("?");
			for (String key : queryParams.keySet()) {
				queryString.append(key).append("=").append(queryParams.get(key)).append("&");
			}
			apiReqUrl += queryString.toString();
		}

		HttpEntity<String> httpEntity = RestTemplateUtils.getHttpEntity(bodyData, heads, apiReqUrl);
		ResponseEntity<T> responseEntity = restTemplate.exchange(apiReqUrl, httpMethod, httpEntity, resultType);
		return responseEntity.getBody();
	}

	public String callApi(String path, Scheme scheme, String httpMethod,
			Map<String, Object> queryParams, Object bodyData,String fileItemName,File file, Map<String, String> heads) {
		
		try{
			//设置url
	        String apiReqUrl = getApiReqUrl(path, scheme);

			if (queryParams != null) {
				StringBuffer queryString = new StringBuffer("?");
				for (String key : queryParams.keySet()) {
					queryString.append(key).append("=").append(queryParams.get(key))
					.append("&");
				}
				apiReqUrl += queryString.toString();
			}
			
	        
	        //设置请求体，注意是LinkedMultiValueMap
			
	        //设置请求头
	        ContentType type = ContentType.parse("multipart/form-data");
	        HttpPost httpPost = new HttpPost(apiReqUrl);
	        if(heads!=null&&!heads.isEmpty()){
	        	for (String key : heads.keySet()) {
	    			String value = heads.get(key);
	    			httpPost.addHeader(key, value);
	    		}
	        }
	        
			HttpClient httpClient = HttpClients.createDefault();
			MultipartEntityBuilder builder = MultipartEntityBuilder.create();
			builder.setMode(HttpMultipartMode.RFC6532);
			String formKey = fileItemName;
			// 判断是否为限制文件类型
			
			builder.addBinaryBody(formKey, new FileInputStream(file),type,file.getName());// 文件流
			
			 
	        if (bodyData != null) {
				queryParams = transBean2Map(bodyData);
				for (String key : queryParams.keySet()) {
					builder.addTextBody(key,(String)queryParams.get(key));
				}
			}

			org.apache.http.HttpEntity entity = builder.build();
			httpPost.setEntity(entity);
			HttpResponse response = httpClient.execute(httpPost);// 执行提交

			org.apache.http.HttpEntity responseEntity = response.getEntity();
			if (responseEntity != null) {
				// 将响应内容转换为字符串
				InputStream content = responseEntity.getContent();
				BufferedInputStream bis = new BufferedInputStream(content);
				ByteArrayOutputStream buf = new ByteArrayOutputStream();
				int result = bis.read();
				while (result != -1) {
					buf.write((byte) result);
					result = bis.read();
				}
				return buf.toString();
			}else{
				return null;
			}
		}catch(Exception e){
			return null;
		}
	}

}
